10. Service Locators

L5 P3 A06 Service Locators

Let's make a ServiceLocator class

Step 1: Create the ServiceLocator

  1. Create the file ServiceLocator.kt in the top level of the main source set.

  1. Define an object called ServiceLocator.
  2. Create database and repository instance variables and set both to null.
  3. Annotate the repository with @Volatile because it could get used by multiple threads (@Volatile is explained in detail here).

Your code should look like this:

ServiceLocator.kt

object ServiceLocator {

    private var database: ToDoDatabase? = null
    @Volatile
    var tasksRepository: TasksRepository? = null

}

Right now the only thing your ServiceLocator needs to do is know how to return a TasksRepository. It'll return a pre-existing DefaultTasksRepository or make and return a new DefaultTasksRepository if needed.

You'll define the following functions:

  1. provideTasksRepository - Either provides an already existing repository or creates a new one. This method should be synchronized on this to avoid, in situations with multiple threads running, ever accidentally creating two repository instances.
  2. createTasksRepository- Code for creating a new repository. Will call createTaskLocalDataSource and create a new TasksRemoteDataSource.
  3. createTaskLocalDataSource - Code for creating a new local data source. Will call createDataBase.
  4. createDataBase - Code for creating a new database.

The completed code is below:

ServiceLocator.kt

object ServiceLocator {

    private var database: ToDoDatabase? = null
    @Volatile
    var tasksRepository: TasksRepository? = null

    fun provideTasksRepository(context: Context): TasksRepository {
        synchronized(this) {
            return tasksRepository ?: createTasksRepository(context)
        }
    }

    private fun createTasksRepository(context: Context): TasksRepository {
        val newRepo = DefaultTasksRepository(TasksRemoteDataSource, createTaskLocalDataSource(context))
        tasksRepository = newRepo
        return newRepo
    }

    private fun createTaskLocalDataSource(context: Context): TasksDataSource {
        val database = database ?: createDataBase(context)
        return TasksLocalDataSource(database.taskDao())
    }

    private fun createDataBase(context: Context): ToDoDatabase {
        val result = Room.databaseBuilder(
            context.applicationContext,
            ToDoDatabase::class.java, "Tasks.db"
        ).build()
        database = result
        return result
    }
}

Good job. Now that you have a ServiceLocator, you'll use it next.